{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "save_and_restore_models.ipynb",
      "version": "0.3.2",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "g_nWetWWd_ns"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "2pHVBk_seED1",
        "colab": {}
      },
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "N_fMsQ-N8I7j",
        "colab": {}
      },
      "source": [
        "#@title MIT License\n",
        "#\n",
        "# Copyright (c) 2017 François Chollet\n",
        "#\n",
        "# Permission is hereby granted, free of charge, to any person obtaining a\n",
        "# copy of this software and associated documentation files (the \"Software\"),\n",
        "# to deal in the Software without restriction, including without limitation\n",
        "# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n",
        "# and/or sell copies of the Software, and to permit persons to whom the\n",
        "# Software is furnished to do so, subject to the following conditions:\n",
        "#\n",
        "# The above copyright notice and this permission notice shall be included in\n",
        "# all copies or substantial portions of the Software.\n",
        "#\n",
        "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
        "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
        "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n",
        "# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
        "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n",
        "# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n",
        "# DEALINGS IN THE SOFTWARE."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "pZJ3uY9O17VN"
      },
      "source": [
        "# モデルの保存と復元"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "M4Ata7_wMul1"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ja/r1/tutorials/keras/save_and_restore_models.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ja/r1/tutorials/keras/save_and_restore_models.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />View source on GitHub</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jqFf_t5y9xep",
        "colab_type": "text"
      },
      "source": [
        "Note: これらのドキュメントは私たちTensorFlowコミュニティが翻訳したものです。コミュニティによる 翻訳は**ベストエフォート**であるため、この翻訳が正確であることや[英語の公式ドキュメント](https://www.tensorflow.org/?hl=en)の 最新の状態を反映したものであることを保証することはできません。 この翻訳の品質を向上させるためのご意見をお持ちの方は、GitHubリポジトリ[tensorflow/docs](https://github.com/tensorflow/docs)にプルリクエストをお送りください。 コミュニティによる翻訳やレビューに参加していただける方は、 [docs-ja@tensorflow.org メーリングリスト](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ja)にご連絡ください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mBdde4YJeJKF"
      },
      "source": [
        "モデルは訓練中にも、訓練が終わったあとも保存できます。このことは、長い訓練時間を掛けなくても、やめたところから再開できるということを意味します。モデルが保存可能であることは、あなたが作ったモデルを他の人と共有できるということでもあります。研究結果であるモデルや手法を公開する際、機械学習の実務家はほとんど次のものを共有します。\n",
        "\n",
        "* モデルを構築するプログラム\n",
        "* 学習済みモデルの重みあるいはパラメータ\n",
        "\n",
        "このデータを共有することで、他の人がモデルだどの様に動作するかを理解したり、新しいデータに試してみたりすることが容易になります。\n",
        "\n",
        "注意：信頼できないプログラムには気をつけましょう。TensorFlowのモデルもプログラムです。詳しくは、[Using TensorFlow Securely](https://github.com/tensorflow/tensorflow/blob/master/SECURITY.md)を参照してください。\n",
        "\n",
        "### オプション\n",
        "\n",
        "TensorFlowのモデルを保存する方法は、使っているAPIによって異なります。このガイドはTensorFlowのモデルを構築し訓練するためのハイレベルなAPIである[tf.keras](https://www.tensorflow.org/r1/guide/keras)を使っています。この他のアプローチについては、TensorFlowの [Save and Restore](https://www.tensorflow.org/r1/guide/saved_model) ガイド、あるいは、[Saving in eager](https://www.tensorflow.org/r1/guide/eager#object-based_saving)を参照してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "xCUREq7WXgvg"
      },
      "source": [
        "## 設定\n",
        "\n",
        "### インストールとインポート"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "7l0MiTOrXtNv"
      },
      "source": [
        "TensorFlowと依存関係のライブラリをインストールし、インポートします。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "RzIOVSdnMYyO",
        "colab": {}
      },
      "source": [
        "!pip install h5py pyyaml"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "SbGsznErXWt6"
      },
      "source": [
        "### サンプルデータセットの取得\n",
        "\n",
        "ここでは、モデルを訓練し重みの保存をデモするために、 [MNIST dataset](http://yann.lecun.com/exdb/mnist/) を使います。デモの実行を速くするため、最初の1,000件のサンプルだけを使います。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "7Nm7Tyb-gRt-",
        "colab": {}
      },
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "import os\n",
        "\n",
        "import tensorflow as tf\n",
        "from tensorflow import keras\n",
        "\n",
        "tf.__version__"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "9rGfFwE9XVwz",
        "colab": {}
      },
      "source": [
        "(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()\n",
        "\n",
        "train_labels = train_labels[:1000]\n",
        "test_labels = test_labels[:1000]\n",
        "\n",
        "train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0\n",
        "test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "anG3iVoXyZGI"
      },
      "source": [
        "### モデルの定義"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "wynsOBfby0Pa"
      },
      "source": [
        "重みの保存と読み込みのデモを行うための簡単なモデルを定義しましょう。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "0HZbJIjxyX1S",
        "colab": {}
      },
      "source": [
        "# 短いシーケンシャルモデルを返す関数\n",
        "def create_model():\n",
        "  model = tf.keras.models.Sequential([\n",
        "    keras.layers.Dense(512, activation=tf.nn.relu, input_shape=(784,)),\n",
        "    keras.layers.Dropout(rate=0.2),\n",
        "    keras.layers.Dense(10, activation=tf.keras.activations.softmax)\n",
        "  ])\n",
        "\n",
        "  model.compile(optimizer=tf.keras.optimizers.Adam(),\n",
        "                loss=tf.keras.losses.sparse_categorical_crossentropy,\n",
        "                metrics=['accuracy'])\n",
        "\n",
        "  return model\n",
        "\n",
        "\n",
        "# 基本的なモデルのインスタンスを作る\n",
        "model = create_model()\n",
        "model.summary()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "soDE0W_KH8rG"
      },
      "source": [
        "## 訓練中にチェックポイントを保存する"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mRyd5qQQIXZm"
      },
      "source": [
        "主な用途は訓練の**途中**あるいは**終了後**にチェックポイントを自動的に保存することです。こうすることにより、再び訓練を行うことなくモデルを使用することができ、また、訓練が中断された場合に、中止したところから再開できます。\n",
        "\n",
        "`tf.keras.callbacks.ModelCheckpoint`がこれを行うためのコールバックです。このコールバックにはチェックポイントを構成するためのいくつかの引数があります。\n",
        "\n",
        "### チェックポイントコールバックの使い方\n",
        "\n",
        "モデルの訓練時に、`ModelCheckpoint`を渡します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "IFPuhwntH8VH",
        "colab": {}
      },
      "source": [
        "checkpoint_path = \"training_1/cp.ckpt\"\n",
        "checkpoint_dir = os.path.dirname(checkpoint_path)\n",
        "\n",
        "# チェックポイントコールバックを作る\n",
        "cp_callback = tf.keras.callbacks.ModelCheckpoint(checkpoint_path,\n",
        "                                                 save_weights_only=True,\n",
        "                                                 verbose=1)\n",
        "\n",
        "model = create_model()\n",
        "\n",
        "model.fit(train_images, train_labels,  epochs = 10,\n",
        "          validation_data = (test_images,test_labels),\n",
        "          callbacks = [cp_callback])  # 訓練にコールバックを渡す\n",
        "\n",
        "# オプティマイザの状態保存についての警告が表示されるかもしれません。\n",
        "# これらの警告は（このノートブックで発生する同様な警告を含めて）\n",
        "# 古い用法を非推奨にするためのもので、無視して構いません。"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "rlM-sgyJO084"
      },
      "source": [
        "この結果、エポックごとに更新される一連のTensorFlowチェックポイントファイルが作成されます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "gXG5FVKFOVQ3",
        "colab": {}
      },
      "source": [
        "!ls {checkpoint_dir}"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "wlRN_f56Pqa9"
      },
      "source": [
        "訓練していない新しいモデルを作ります。重みだけからモデルを復元する場合には、元のモデルと同じアーキテクチャのモデルが必要です。モデルのアーキテクチャが同じであるため、モデルの異なる**インスタンス**であっても重みを共有することができるのです。\n",
        "\n",
        "訓練していない全く新しいモデルを作り、テストデータセットで評価します。訓練をしていないモデルは偶然のレベル（正解率10%以下）の性能しか無いはずです。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Fp5gbuiaPqCT",
        "colab": {}
      },
      "source": [
        "model = create_model()\n",
        "\n",
        "loss, acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Untrained model, accuracy: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "1DTKpZssRSo3"
      },
      "source": [
        "次に、チェックポイントから重みをロードし、再び評価します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "2IZxbwiRRSD2",
        "colab": {}
      },
      "source": [
        "model.load_weights(checkpoint_path)\n",
        "loss,acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "bpAbKkAyVPV8"
      },
      "source": [
        "### チェックポイントコールバックのオプション\n",
        "\n",
        "このコールバックには、チェックポイントに一意な名前をつけたり、チェックポイントの頻度を調整するためのオプションがあります。\n",
        "\n",
        "新しいモデルを訓練し、5エポックごとに一意な名前のチェックポイントを保存します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "mQF_dlgIVOvq",
        "colab": {}
      },
      "source": [
        "# ファイル名に(`str.format`を使って)エポック数を埋め込みます\n",
        "checkpoint_path = \"training_2/cp-{epoch:04d}.ckpt\"\n",
        "checkpoint_dir = os.path.dirname(checkpoint_path)\n",
        "\n",
        "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n",
        "    checkpoint_path, verbose=1, save_weights_only=True,\n",
        "    # 重みを5エポックごとに保存します\n",
        "    period=5)\n",
        "\n",
        "model = create_model()\n",
        "model.fit(train_images, train_labels,\n",
        "          epochs = 50, callbacks = [cp_callback],\n",
        "          validation_data = (test_images,test_labels),\n",
        "          verbose=0)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "1zFrKTjjavWI"
      },
      "source": [
        "次に、出来上がったチェックポイントを確認し、最後のものを選択します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "p64q3-V4sXt0",
        "colab": {}
      },
      "source": [
        "! ls {checkpoint_dir}"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "1AN_fnuyR41H",
        "colab": {}
      },
      "source": [
        "latest = tf.train.latest_checkpoint(checkpoint_dir)\n",
        "latest"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Zk2ciGbKg561"
      },
      "source": [
        "注意：デフォルトのtensorflowフォーマットは、直近の5つのチェックポイントのみを保存します。\n",
        "\n",
        "テストのため、モデルをリセットし最後のチェックポイントをロードします。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "3M04jyK-H3QK",
        "colab": {}
      },
      "source": [
        "model = create_model()\n",
        "model.load_weights(latest)\n",
        "loss, acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "c2OxsJOTHxia"
      },
      "source": [
        "## これらのファイルは何？"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JtdYhvWnH2ib"
      },
      "source": [
        "上記のコードでは、重みだけをバイナリで[checkpoint](https://www.tensorflow.org/r1/guide/saved_model#save_and_restore_variables)形式の一連のファイルに保存します。チェックポイントには、次のものが含まれます。\n",
        "\n",
        "* １つ以上のモデルの重みの断片\n",
        "* どの重みがどの断片に保存されているかを示すインデックスファイル\n",
        "\n",
        "1台のマシンだけでモデルの訓練を行っている場合には、`.data-00000-of-00001`のようなサフィックスのついたファイルが1つだけ作成されます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "S_FA-ZvxuXQV"
      },
      "source": [
        "## 手動で重みを保存する\n",
        "\n",
        "上記では重みをモデルにロードする方法を見ました。\n",
        "\n",
        "手動で重みを保存するのも同じ様に簡単です。`Model.save_weights` メソッドを使います。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "R7W5plyZ-u9X",
        "colab": {}
      },
      "source": [
        "# 重みの保存\n",
        "model.save_weights('./checkpoints/my_checkpoint')\n",
        "\n",
        "# 重みの復元\n",
        "model = create_model()\n",
        "model.load_weights('./checkpoints/my_checkpoint')\n",
        "\n",
        "loss,acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "kOGlxPRBEvV1"
      },
      "source": [
        "## モデル全体の保存\n",
        "\n",
        "重みの値、モデルの設定、そして（構成によりますが<sup>※訳注1</sup>）オプティマイザの設定までも含んだモデル全体をファイルに保存することができます。これにより、モデルのある時点の状態を保存し、オリジナルのPythonコードにアクセスしなくとも、中断したところから訓練を再開することができます。\n",
        "\n",
        "（※訳注1：tf.trainモジュールに含まれるオプティマイザではないオプティマイザを使用しているモデルをHDF5ファイルに保存する場合にはオプティマイザの設定を保存できます。）\n",
        "\n",
        "完全に機能するモデルを保存できるのは便利です。保存したモデルをTensorFlow.js ([HDF5](https://js.tensorflow.org/r1/tutorials/import-keras.html), [Saved Model](https://js.tensorflow.org/r1/tutorials/import-saved-model.html))でロードし、ブラウザで訓練したり、実行したりすることができるほか、TensorFlow Lite ([HDF5](https://www.tensorflow.org/lite/convert/python_api#exporting_a_tfkeras_file_), [Saved Model](https://www.tensorflow.org/lite/convert/python_api#exporting_a_savedmodel_))\n",
        "を使ってモバイルデバイスで実行できるように変換することも可能です。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "SkGwf-50zLNn"
      },
      "source": [
        "### HDF5ファイルとして\n",
        "\n",
        "Kerasでは、[HDF5](https://en.wikipedia.org/wiki/Hierarchical_Data_Format) 標準を使った基本的なファイルフォーマットが利用できます。ここでの利用目的では、保存されたモデルは単独のバイナリラージオブジェクト（blob）として扱うことができます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "m2dkmJVCGUia",
        "colab": {}
      },
      "source": [
        "model = create_model()\n",
        "\n",
        "model.fit(train_images, train_labels, epochs=5)\n",
        "\n",
        "# モデル全体を１つのHDF5ファイルに保存します。\n",
        "model.save('my_model.h5')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "GWmttMOqS68S"
      },
      "source": [
        "保存したファイルを使ってモデルを再作成します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "5NDMO_7kS6Do",
        "colab": {}
      },
      "source": [
        "# 重みとオプティマイザを含む全く同じモデルを再作成\n",
        "new_model = keras.models.load_model('my_model.h5')\n",
        "new_model.summary()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JXQpbTicTBwt"
      },
      "source": [
        "正解率を検査します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "jwEaj9DnTCVA",
        "colab": {}
      },
      "source": [
        "loss, acc = new_model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "dGXqd4wWJl8O"
      },
      "source": [
        "この方法では、次のすべてが保存されます。\n",
        "\n",
        "* 重みの値\n",
        "* モデルの設定（アーキテクチャ）\n",
        "* オプティマイザの設定\n",
        "\n",
        "Kerasは保存する際にアーキテクチャを調べます。いまのところ、TensorFlowのオプティマイザ（`tf.train`に含まれるもの）を保存することはできません。TensorFlowのオプティマイザを使用している場合には、モデルをロードしたあと再コンパイルする必要があり、オプティマイザの状態は失われます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "kPyhgcoVzqUB"
      },
      "source": [
        "### `saved_model`として"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "LtcN4VIb7JkK"
      },
      "source": [
        "注意：この手法による`tf.keras`モデルの保存は実験的なもので、将来のバージョンで変更される可能性があります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "DSWiSB0Q8c46"
      },
      "source": [
        "新しいモデルを作ります。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "sI1YvCDFzpl3",
        "colab": {}
      },
      "source": [
        "model = create_model()\n",
        "\n",
        "model.fit(train_images, train_labels, epochs=5)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "iUvT_3qE8hV5"
      },
      "source": [
        "`saved_model`を作成します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "sq8fPglI1RWA",
        "scrolled": true,
        "colab": {}
      },
      "source": [
        "saved_model_path = tf.contrib.saved_model.save_keras_model(model, \"./saved_models\")"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "MjpmyPfh8-1n"
      },
      "source": [
        "SavedModel はタイムスタンプ付きのディレクトリに保存されます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "ZtOvxA7V0iTv",
        "colab": {}
      },
      "source": [
        "!ls saved_models/"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "B7qfpvpY9HCe"
      },
      "source": [
        "保存されたモデル(SavedModel)から新しいKerasモデルをリロードします。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "0YofwHdN0pxa",
        "colab": {}
      },
      "source": [
        "new_model = tf.contrib.saved_model.load_keras_model(saved_model_path)\n",
        "new_model"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "uWwgNaz19TH2"
      },
      "source": [
        "復元されたモデルを実行します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Pc9e6G6w1AWG",
        "scrolled": true,
        "colab": {}
      },
      "source": [
        "# モデルを評価する前にコンパイルする必要があります。\n",
        "# モデルをデプロイするだけであればこのステップは不要です。\n",
        "\n",
        "new_model.compile(optimizer=tf.keras.optimizers.Adam(),\n",
        "              loss=tf.keras.losses.sparse_categorical_crossentropy,\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "# モデルを評価します。\n",
        "loss, acc = new_model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "eUYTzSz5VxL2"
      },
      "source": [
        "## この先は？\n",
        "\n",
        "`tf.keras`を使った保存とロードのクイックガイドでした。\n",
        "\n",
        "* [tf.keras guide](https://www.tensorflow.org/r1/guide/keras) には`tf.keras`での保存とロードについて、もう少し記載されています\n",
        "\n",
        "* Eager Executionでの保存については[Saving in eager](https://www.tensorflow.org/r1/guide/eager#object_based_saving) を参照ください\n",
        "\n",
        "* [Save and Restore](https://www.tensorflow.org/r1/guide/saved_model)ガイドには、TensorFlowでの保存についてローレベルの詳細が記載されています"
      ]
    }
  ]
}